﻿using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using Microsoft.SharePoint.Administration;

namespace Vasyaya.SharePointExtensions.CurrentVisitors.WebParts
{
    [ToolboxItemAttribute(false)]
    public class CurrentVisitorsWebPart : WebPart
    {
        private const int ActivityPeriodDefault = 5;
        private const string CommaMarkup = "<span style=\"vertical-align: top\">, </span>";

        // B2C0B444-3914-4ACB-A0B8-7CF50A8F7AA0 : SharePoint Server 2010 Standard Trial
        // 3FDFBCC8-B3E4-4482-91FA-122C6432805C : SharePoint Server 2010 Standard
        // 88BED06D-8C6B-4E62-AB01-546D6005FE97 : SharePoint Server 2010 Enterprise Trial
        // D5595F62-449B-4061-B0B2-0CBAD410BB51 : SharePoint Server 2010 Enterprise
        private Guid[] serverProducts2010 = { 
                       new Guid("B2C0B444-3914-4ACB-A0B8-7CF50A8F7AA0"), 
                       new Guid("3FDFBCC8-B3E4-4482-91FA-122C6432805C"), 
                       new Guid("88BED06D-8C6B-4E62-AB01-546D6005FE97"), 
                       new Guid("D5595F62-449B-4061-B0B2-0CBAD410BB51") };

        public CurrentVisitorsWebPart()
        {
            ActivityPeriod = ActivityPeriodDefault;
        }

        /// <summary>
        /// Activity Period.
        /// </summary>
        [WebBrowsable(true), WebDisplayName("Activity Period (minutes)"), WebDescription("Period in which a latest user's activity is accounted to decide if he/she is currently visiting a site collection."), Personalizable(PersonalizationScope.Shared), Category("Custom Properties"), DefaultValue(ActivityPeriodDefault)]
        public int ActivityPeriod { get; set; }

        /// <summary>
        /// Create Web Part controls.
        /// </summary>
        protected override void CreateChildControls()
        {
            try
            {
                base.CreateChildControls();

                WebControl container = new WebControl(System.Web.UI.HtmlTextWriterTag.Div);
                container.CssClass = "ms-vb-user";

                StringBuilder sb = new StringBuilder();
                
                SPSite siteContext = SPContext.Current.Site;

                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite siteWithElevatedPrivileges = new SPSite(siteContext.ID))
                    {
                            // Build an audit query for current site collection.
                            SPAuditQuery auditQuery = new SPAuditQuery(siteWithElevatedPrivileges);
                            auditQuery.AddEventRestriction(SPAuditEventType.View);
                            auditQuery.SetRangeStart(DateTime.UtcNow.AddMinutes(-ActivityPeriod));
                            auditQuery.SetRangeEnd(DateTime.UtcNow);

                            // Retrieve audit entried for specified period.
                            SPAuditEntryCollection auditEntries = siteWithElevatedPrivileges.Audit.GetEntries(auditQuery);

                            // Check if SharePoint 2010 or 2013
                            bool isSharePoint2010 = SPFarm.Local.Products.Any(t => serverProducts2010.Contains(t));

                            List<int> usersList = new List<int>();
                            int id = 1000;

                            foreach (SPAuditEntry entry in auditEntries)
                            {
                                if (!usersList.Contains(entry.UserId) && entry.UserId != -1 && entry.UserId != siteWithElevatedPrivileges.SystemAccount.ID)
                                {
                                    SPUser user = siteWithElevatedPrivileges.OpenWeb().AllUsers.GetByID(entry.UserId);

                                    if (!user.LoginName.Contains("NT AUTHORITY")) 
                                    {
                                        // If user has email then render presense control
                                        if (!String.IsNullOrEmpty(user.Email))
                                        {
                                            // Check if SharePoint 2010 or 2013
                                            if (isSharePoint2010)
                                            {
                                                sb.AppendFormat(
                                                    "<span class=\"ms-imnSpan\">" +
                                                        "<img border='0' src='/_layouts/images/imnhdr.gif' onload=\"IMNRC('{0}')\" ShowOfflinePawn='1' alt='' id='imn_{3},type=sip'/>" +
                                                            "<a style='margin-left: 2px;' href='/_layouts/userdisp.aspx?ID={1}'>{2}</a>" +
                                                    "</span>",
                                                    user.Email, user.ID.ToString(), user.Name, id.ToString());

                                                id ++;
                                            }
                                            else
                                            {
                                                sb.AppendFormat(
                                                    "<span>" +
                                                     "<span class='ms-imnSpan'>" +
                                                      "<a href='#' onclick='IMNImageOnClick(event);return false;' class='ms-imnlink ms-spimn-presenceLink' >" +
                                                       "<span class='ms-spimn-presenceWrapper ms-imnImg ms-spimn-imgSize-10x10'>" +
                                                        "<img name='imnmark' title='' ShowOfflinePawn='1' class='ms-spimn-img ms-spimn-presence-disconnected-10x10x32' src='/_layouts/15/images/spimn.png' alt='User Presence' sip='{0}' id='imn_{3},type=sip' />" +
                                                       "</span>" +
                                                      "</a>" +
                                                     "</span>" +
                                                    "<span>" +
                                                     "<a href='#' onclick='IMNImageOnClick(event);return false;' class='ms-imnlink' tabIndex='-1'>" +
                                                    "<img name='imnmark' title='' ShowOfflinePawn='1' class=' ms-hide' src='/_layouts/15/images/spimn.png' alt='User Presence' sip='{0}' id='imn_{4},type=sip' /></a>" +
                                                            "<a class='ms-subtleLink' onclick='GoToLinkOrDialogNewWindow(this);return false;' href='/_layouts/15/userdisp.aspx?ID={1}'>{2}</a>" +
                                                    "</span>" +
                                                    "</span>",
                                                    user.Email, user.ID.ToString(), user.Name, id.ToString(), (id + 1).ToString());

                                                id += 2;
                                            }
                                        }
                                        else
                                        {
                                            sb.AppendFormat("<a href='/_layouts/userdisp.aspx?ID={0}'>{1}</a>", user.ID.ToString(), user.Name);
                                        }

                                        sb.Append(CommaMarkup);

                                        usersList.Add(entry.UserId);
                                    }
                                }
                            }

                    

                    }

                });

                if (sb.Length > 0)
                {
                    // Remove last comma.
                    sb.Remove(sb.Length - CommaMarkup.Length, CommaMarkup.Length);

                    container.Controls.Add(new LiteralControl(sb.ToString()));
                }
                else
                {
                    container.Controls.Add(new LiteralControl("<span>No visitors.</span>"));
                }

                Controls.Add(container);
            }
            catch (Exception ex)
            {
                LogError(ex);
            }
        }


        /// <summary>
        /// Dispalay and log exception.
        /// </summary>
        private void LogError(Exception ex)
        {
            try
            {
                // Log into ULS
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    SPDiagnosticsService.Local.WriteTrace(0,
                                                      new SPDiagnosticsCategory("CurrentVisitorsWebPart", TraceSeverity.Unexpected,
                                                                                EventSeverity.Error),
                                                      TraceSeverity.Unexpected, ex.ToString(), ex.Message);
                });
            }
            catch { }
            finally
            {
                Controls.Add(new LiteralControl("<span style=\"color:red;\"><b>Error:&nbsp;</b>"));
                Controls.Add(new LiteralControl(ex.Message));
                Controls.Add(new LiteralControl(" See details in the ULS.</span>"));
            }
        }

    }
}
